#ifndef _TOOLS_3D_H_
#define _TOOLS_3D_H_

////////////////////////////////////////////////////////////////////////////////
// Includes
////////////////////////////////////////////////////////////////////////////////

#include "Point3D.hpp"
#include "Vector3D.hpp"

////////////////////////////////////////////////////////////////////////////////
// Namespaces
////////////////////////////////////////////////////////////////////////////////

namespace Toolkit {

////////////////////////////////////////////////////////////////////////////////
// Implementation
////////////////////////////////////////////////////////////////////////////////

/// 3D Camera
template <typename T>
struct Camera {

	/// Default constructor
	Camera() : location(0., 0., 0.), looking(0., 0., 1.), vuv(0., 1., 0.) {}

	/// Translates the camera from the given vector in the camera basis
	void Translate(const Types::Vector3D<T> & v) {
		if (v.x != 0.) this->location += (this->looking*this->vuv) * v.x;
		if (v.y != 0.) this->location += this->vuv * v.y;
		if (v.z != 0.) this->location += this->looking * v.z;
	}

	/// Rotate horizontally
	void RotateH(const double angle) {
		this->looking = cos(angle) * this->looking - sin(angle) * (this->looking*this->vuv);
	}

	/// Rotate vertically
	void RotateV(const double angle) {
		Types::Vector3D<T> old_looking(this->looking);
		this->looking = cos(angle) * this->looking + sin(angle) * this->vuv;
		this->vuv = cos(angle) * this->vuv - sin(angle) * old_looking;
	}

	/// Rotate around the looking vector
	void RotateL(const double angle) {
		this->vuv = cos(angle) * this->vuv - sin(angle) * (this->looking*this->vuv);
	}

	/// Camera location
	Types::Point3D<T> location;

	/// Looking direction
	Types::Vector3D<T> looking;

	/// View up vector
	Types::Vector3D<T> vuv;

};

////////////////////////////////////////////////////////////////////////////////
// Closing Namespaces
////////////////////////////////////////////////////////////////////////////////

}

////////////////////////////////////////////////////////////////////////////////

#endif
